<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>TWaver HTML5</title>
  <script src="../libs/twaver.js"></script>
  <script src="../libs/stats.min.js"></script>
  <script>
  var box = new twaver.ElementBox();
  var network = new twaver.vector.Network(box);
  var overView = new twaver.vector.Overview(network);
  var autoLayouter = new twaver.layout.AutoLayouter(box);
  var stats = new Stats();
  stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom

  function init() {
    document.body.appendChild(stats.dom);
    initNetwork();
    initDataBox();
  }

  function initNetwork() {
    var view = network.getView();
    document.body.appendChild(view);
    network.getView().style.backgroundColor = '#a3cbe2';
    network.getView().style.backgroundColor = '#333';
    overView.setFillColor("rgba(184,211,240,0.5)");
    var overviewDiv = document.createElement("div");
    overviewDiv.style.background = "#424242";
    overviewDiv.style.position = "absolute";
    overviewDiv.style.right = "10px";
    overviewDiv.style.bottom = "20px";
    overviewDiv.style.width = "300px";
    overviewDiv.style.height = "200px";
    var overviewView = overView.getView();
    overviewView.style.left = '10px';
    overviewView.style.right = '10px';
    overviewView.style.top = '10px';
    overviewView.style.bottom = '10px';
    overviewView.style.background = twaver.Colors.orange;
    overviewDiv.appendChild(overviewView);
    document.body.appendChild(overviewDiv);

    function findDimensions() {
      if (window.innerWidth)
        winWidth = window.innerWidth;
      else if ((document.body) && (document.body.clientWidth))
        winWidth = document.body.clientWidth;
      if (window.innerHeight)
        winHeight = window.innerHeight;
      else if ((document.body) && (document.body.clientHeight))
        winHeight = document.body.clientHeight;
      if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientWidth) {
        winHeight = document.documentElement.clientHeight;
        winWidth = document.documentElement.clientWidth;
      }
    }

    findDimensions();
    network.adjustBounds({
      x: 0,
      y: 0,
      width: winWidth,
      height: winHeight
    });

    network.validate = function() {
      stats.begin();
      if (!this._invalidate) {
        return;
      }
      // if (!isNodejs && this._view.offsetWidth === 0 && this._view.offsetHeight === 0) {
      //   return;
      // }
      this._invalidate = false;
      this._isValidating = true;
      this.fireViewEvent({
        kind: 'validateStart'
      });
      this.validateImpl();
      this.fireViewEvent({
        kind: 'validateEnd'
      });
      this._isValidating = false;
      stats.end();
    }
    network.setLinkPathFunction(function(linkUI, defaultPoints) {
      var link = linkUI._element;
      if (link.getClient('link.type') === 'flowLink') {
        var f = linkUI.getFromPoint();
        var t = linkUI.getToPoint();
        var factor = link.getClient('factor') || 1;

        var points = new twaver.List();
        points.add(f);
        points.add(t);

        var lineLength = _twaver.math.getDistance(f, t);
        var offset = -lineLength / 5;
        var m = {
          x: (f.x + t.x) / 2 + offset,
          y: (f.y + t.y) / 2 + offset + Math.pow(-1, factor) * factor * 20
        }

        var cps = new twaver.List();
        cps.add(m);
        cps.add(t);

        points.removeAt(1);
        points.add(cps);
        link.setClient('controlPointX', m.x);
        link.setClient('controlPointY', m.y);
        // if(m.y > (f.y + t.y)/2){
        //   link.setClient('controlPointOritation','top');
        // }else{
        //   link.setClient('controlPointOritation','bottom');
        // }
        return points;
      } else {
        return defaultPoints;
      }
    });
  }

  function initDataBox() {
    var centerX = 600;
    var centerY = 300;
    var radius = 300;
    var node1 = new twaver.Node({
      centerLocation: {
        x: centerX,
        y: centerY
      },
    });
    box.add(node1);

    for (var i = 0, n = 3; i < n; i++) {
      var x = centerX + (radius * Math.cos(Math.PI * 2 / n * i));
      var y = centerY + (radius * Math.sin(Math.PI * 2 / n * i));

      var node2 = new twaver.Node({
        centerLocation: {
          x: x,
          y: y
        },
        name: 'to',
      });
      box.add(node2);

      var color = twaver.Util.randomColor();
      var link = new FlowLink({
        clients: {
          box: box,
          factor: i,
          'link.type': 'flowLink',
          'fillColor': color,
          'shadowColor': color,
          'tail': 30,
          'tailRadius': 2,
          'tailFactor': 1.5,
        },
        styles: {
          'link.color': color,
          'link.width': 0.4,
          'link.pattern': [4, 2],
        }
      }, node1, node2);
      link.setAnimate(4000);
      box.add(link);
      link.playAnimate();
    }
    for (var i = 0, n = 3; i < n; i++) {
      var x = centerX + (radius * Math.cos(Math.PI * 2 / n * i));
      var y = centerY + (radius * Math.sin(Math.PI * 2 / n * i));

      var node2 = new twaver.Node({
        centerLocation: {
          x: x,
          y: y
        },
        name: 'to',
      });
      box.add(node2);

      var color = twaver.Util.randomColor();
      var link = new FlowLink({
        clients: {
          box: box,
          factor: i,
          'link.type': 'flowLink',
          'fillColor': color,
          'shadowColor': color,
          'tail': 30,
          'tailRadius': 2,
          'tailFactor': 1.5,
        },
        styles: {
          'link.color': color,
          'link.width': 0.4,
          'link.pattern': [4, 2],
        }
      }, node1, node2);
      link.setAnimate(4000);
      box.add(link);
      link.playAnimate();
    }
  }

  function FlowLink() {
    FlowLink.superClass.constructor.apply(this, arguments);
  }

  twaver.Util.ext(FlowLink, twaver.Link, {
    getVectorUIClass: function() {
      return FlowLinkUI;
    },
    playAnimate: function(dur) {
      this.animate.play();
    },
    setAnimate: function(dur) {
      var dur = dur || 1200;
      var self = this;
      var fNode, tNode;

      fNode = self.getFromNode();
      tNode = self.getToNode();

      this.animate = new twaver.Animate({
        from: 0,
        to: 1,
        repeat: Number.POSITIVE_INFINITY,
        // repeat: 2,
        reverse: false,
        dur: dur,
        onPlay: function() {

        },
        onUpdate: function(value) {
          self.setClient('percent', value);
          if (value >= 1) self.setClient('over', true);
          else self.setClient('over', false);
        },
        onDone: function() {

        }
      });
    }
  });

  function FlowLinkUI() {
    FlowLinkUI.superClass.constructor.apply(this, arguments);
  }

  twaver.Util.ext(FlowLinkUI, twaver.vector.LinkUI, {
    paintBody: function(ctx) {
      var link = this.getElement();
      if (link.getClient('over')) return;
      var fillColor = link.getClient('fillColor');
      var shadowColor = link.getClient('shadowColor');
      var tail = link.getClient('tail');
      var percent = link.getClient('percent');
      var paths = this.getLinkPoints();
      var offset = this.getLineLength() * percent;
      var tailFactor = link.getClient('tailFactor') || 1.5;
      var tailRadius = link.getClient('tailRadius') || 2;
      var point;
      var fromPoint = this._element.getFromAgent().getCenterLocation();
      var toPoint = this._element.getToAgent().getCenterLocation();
      var point = _twaver.math.calculatePointInfoAlongLine(paths, true, offset, 0).point;
      var points = new twaver.List();

      points.add(fromPoint);
      points.add(point);

      if (link.getClient('controlPointX')) {
        var controlPoint = {
          x: link.getClient('controlPointX'),
          y: link.getClient('controlPointY')
        };
        var c1 = {
          x: (fromPoint.x + controlPoint.x) / 2,
          y: (fromPoint.y + controlPoint.y) / 2
        };
        var c2 = {
          x: (toPoint.x + controlPoint.x) / 2,
          y: (toPoint.y + controlPoint.y) / 2
        };
        var c3 = {
          x: (c1.x + c2.x) / 2,
          y: (c1.y + c2.y) / 2
        };
        points.add(c1);
        points.add(c2);
        points.add(c3);
        // points.add(controlPoint);
      }
      var rect = _twaver.math.getRect(points);

      if (fromPoint.x < toPoint.x) {
        ctx.rect(rect.x, rect.y, Math.abs(point.x - fromPoint.x) + 1.5, rect.height);
      } else {
        ctx.rect(point.x - 1.5, rect.y, Math.abs(point.x - fromPoint.x), rect.height);
      }
      ctx.clip();
      FlowLinkUI.superClass.paintBody.call(this, ctx);

      for (var i = 0, count = tail; i < count; i++) {
        var v = i / count;
        point = _twaver.math.calculatePointInfoAlongLine(paths, true, offset - (count - i) *
          tailFactor, 0).point;
        ctx.globalAlpha = v * v;
        ctx.shadowBlur = 10;
        ctx.shadowColor = shadowColor;
        ctx.beginPath();
        ctx.fillStyle = fillColor;
        ctx.arc(point.x, point.y, tailRadius, 0, Math.PI * 2, false);
        ctx.fill();
      }
      for (var i = 0, count = tail; i < count; i++) {
        var v = i / count;
        point = _twaver.math.calculatePointInfoAlongLine(paths, true, offset - (count - i) * 1,
          0).point;
        ctx.globalAlpha = v * v;
        ctx.shadowBlur = 1;
        ctx.shadowColor = shadowColor;
        ctx.beginPath();
        ctx.fillStyle = 'white';
        ctx.arc(point.x, point.y, 1, 0, Math.PI * 2, false);
        ctx.fill();
      }
    }
  });
  </script>
</head>

<body onload="init()">
</body>

</html>